HihoCoder-1175 拓扑排序·二(拓扑序 判断循环图)

描述

传送门:HihoCoder-1175 拓扑排序·二

小Hi和小Ho所在学校的校园网被黑客入侵并投放了病毒。这事在校内BBS上立刻引起了大家的讨论,当然小Hi和小Ho也参与到了其中。从大家各自了解的情况中,小Hi和小Ho整理得到了以下的信息:

校园网主干是由N个节点(编号1..N)组成,这些节点之间有一些单向的网路连接。若存在一条网路连接(u,v)链接了节点u和节点v,则节点u可以向节点v发送信息,但是节点v不能通过该链接向节点u发送信息。
在刚感染病毒时,校园网立刻切断了一些网络链接,恰好使得剩下网络连接不存在环,避免了节点被反复感染。也就是说从节点i扩散出的病毒,一定不会再回到节点i。
当1个病毒感染了节点后,它并不会检查这个节点是否被感染,而是直接将自身的拷贝向所有邻居节点发送,它自身则会留在当前节点。所以一个节点有可能存在多个病毒。
现在已经知道黑客在一开始在K个节点上分别投放了一个病毒。

举个例子,假设切断部分网络连接后学校网络如下图所示,由4个节点和4条链接构成。最开始只有节点1上有病毒。

最开始节点1向节点2和节点3传送了病毒,自身留有1个病毒:

其中一个病毒到达节点2后,向节点3传送了一个病毒。另一个到达节点3的病毒向节点4发送自己的拷贝:

当从节点2传送到节点3的病毒到达之后,该病毒又发送了一份自己的拷贝向节点4。此时节点3上留有2个病毒:

最后每个节点上的病毒为:

小Hi和小Ho根据目前的情况发现一段时间之后,所有的节点病毒数量一定不会再发生变化。那么对于整个网络来说,最后会有多少个病毒呢?

输入描述

第1行:3个整数N,M,K,1≤K≤N≤100,000,1≤M≤500,000

第2行:K个整数A[i],A[i]表示黑客在节点A[i]上放了1个病毒。1≤A[i]≤N

第3..M+2行:每行2个整数 u,v,表示存在一条从节点u到节点v的网络链接。数据保证为无环图。1≤u,v≤N

输出描述

第1行:1个整数,表示最后整个网络的病毒数量 MOD 142857

示例

输入

1
2
3
4
5
6
4 4 1
1
1 2
1 3
2 3
3 4

输出

1
6

题解

题目大意

中文题面

思路

从入度为0的节点开始,对于这些节点,它并不会再增加病毒数量。那么我们就根据它所关联的连接将病毒分发出去,然后这个节点就没有作用了。那不妨就删掉好了,它所关联的边也删掉,这样图中又会产生一些新的没有入度的节点。这样一直删点,直到所有的点都被删掉,将所有点的病毒数量加起来就是总的病毒数。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <cstdio>
#include <queue>
#include <cmath>
const int MAXN = 5*1e5, INF = 0x3f3f3f3f, MOD = 142857;
using namespace std;
int n, m, k, u, v, x;
int inDeg[MAXN], virus[MAXN];
vector<int> E[MAXN];

void topsort(){
queue<int> q;
for(int i = 1; i <= n; i++)
if(!inDeg[i])
q.push(i);
while(!q.empty()){
int now = q.front();
q.pop();
for(int i = 0; i < E[now].size(); i++){
if(--inDeg[E[now][i]] == 0){
q.push(E[now][i]);
}
virus[E[now][i]] = (virus[E[now][i]] + virus[now])%MOD;
}
}
}

int main(){
while(~scanf("%d %d %d", &n, &m, &k)){
memset(inDeg, 0, sizeof(inDeg));
memset(virus, 0, sizeof(virus));
for(int i = 0; i <= n; i++) E[i].clear();
for(int i = 0; i < k; i++){
scanf("%d", &x);
virus[x]++;
}
for(int i = 0; i < m; i++){
scanf("%d %d", &u, &v);
E[u].push_back(v);
inDeg[v]++;
}
topsort();
int ans = 0;
for(int i = 1; i <= n; i++){
ans = (ans + virus[i])%MOD;
}
printf("%d\n", ans);
}
}
/*
4 4 1
1
1 2
1 3
2 3
3 4
*/